# -*- coding: utf-8 -*-

import time
import json
import logging

from PyQt4 import QtGui
from PyQt4.QtCore import Qt
from PyQt4.Qt import SIGNAL, QTimer

from chessboard import ChessBoard, NON_FLAG, WHITE_FLAG, BLACK_FLAG
from server import netstream
from ui.game_ui import Ui_MainWindow
from musicplay import MusicPlay


class ChessClient(QtGui.QMainWindow, Ui_MainWindow):

    def __init__(self, ip, port, username, ns):
        QtGui.QMainWindow.__init__(self, None)
        self.ip = ip
        self.port = port
        self.username = username
        self.ns = ns
        self.reconnect = False
        self.saveNext = False
        self.saveStart = False
        self.saveGive = False
        self.saveRegret = False
        self.saveAgain = False
        self.saveLeave = False
        self.saveSend = False

    # 初始化配置
    def __init_config(self):
        self.timer = QTimer()
        self.tableList = [ 0 for i in xrange(25)]
        self.scoreList = {}
        self.loopCount = 40
        self.tickCount = 100
        self.musicplay = MusicPlay()

    # 初始化UI
    def __init_ui(self):
        self.setupUi(self)
        self.setWindowTitle(self.username)
        self.userInfo = ChessBoard(self.username, self.chessBoard, self.inforShow)
        self.setButtonStatus(False, False, False, False, False, False)
        self.groupTalk.setReadOnly(True)
        self.singleTalk.setReadOnly(True)
        # 按钮处理
        self.connect(self.start, SIGNAL('clicked()'), self.startChess)
        self.connect(self.giveUp, SIGNAL('clicked()'), self.loseChess)
        self.connect(self.undo, SIGNAL('clicked()'), self.undoChess)
        self.connect(self.again, SIGNAL('clicked()'), self.againChess)
        self.connect(self.left, SIGNAL('clicked()'), self.leaveChess)
        # 进入房间
        self.room.itemDoubleClicked.connect(self.intoTable)
        # 群聊消息
        self.connect(self.groupSend, SIGNAL("clicked()"), self.sendGroupMessage)
        self.connect(self.groupEdit, SIGNAL("returnPressed()"), self.sendGroupMessage)
        # 私人聊天
        self.connect(self.singleSend, SIGNAL("clicked()"), self.sendSingleMessage)
        self.connect(self.singleEdit, SIGNAL("returnPressed()"), self.sendSingleMessage)
        # 定时器触发
        self.connect(self.timer, SIGNAL("timeout()"), self.check)

    # 设置按钮状态
    def setButtonStatus(self, startStatus, giveUpStatus, undoStatus, againStatus, leftStatus, singleSendStatus):
        self.start.setEnabled(startStatus)
        self.giveUp.setEnabled(giveUpStatus)
        self.undo.setEnabled(undoStatus)
        self.again.setEnabled(againStatus)
        self.left.setEnabled(leftStatus)
        self.singleSend.setEnabled(singleSendStatus)

    # 开始
    def startChess(self):
        self.setButtonStatus(False, True, True, False, False, True)
        self.userInfo.isReady = True
        message = {'sid':100,'cid':1005,'message':'start','user':self.userInfo.name,'opponent':self.userInfo.opponent}
        self.ns.send(json.dumps(message))

    # 认输
    def loseChess(self):
        self.setButtonStatus(False, False, False, True, True, True)
        self.userInfo.isNext = False
        data = {'sid':100,'cid':1009,'winner':self.userInfo.opponent,'loser':self.userInfo.name,'chessType':self.userInfo.chessType}
        self.ns.send(json.dumps(data))
        self.ns.process()
        self.inforShow.setText(u"你认输了")
        self.musicplay.playLose()

    # 悔棋
    def undoChess(self):
        if not self.userInfo.isNext:
            return
        if len(self.userInfo.path) < 2:
            self.inforShow.setText(u"你还没下，\n不得悔棋")
            return
        else:
            self.userInfo.isNext = False
            self.inforShow.setText(u"悔棋等待中")
            data = {'sid':100, 'cid':1010,'message':'undo','userlist':[self.userInfo.opponent],'user':self.userInfo.name}
            self.ns.send(json.dumps(data))
            self.ns.process()

    # 再来一局
    def againChess(self):
        message = {'sid':100,'cid':1012,'message':'again','userlist':[self.userInfo.opponent],'user':self.userInfo.name}
        self.ns.send(json.dumps(message))

    # 离开房间
    def leaveChess(self):
        self.userInfo.clearChessBoard()
        self.player1.setText(u"玩家1：")
        self.score_player1.setText(u"分数：")
        self.player2.setText(u"玩家2：")
        self.score_player2.setText(u"分数：")
        self.userInfo.isInto = False
        data = {'sid':100,'cid':1003,'roomid':self.userInfo.roomid - 1,'tableid':self.userInfo.tableid - 1,
                'user':self.userInfo.name,'opponent':self.userInfo.opponent}
        self.userInfo.opponent = None
        self.userInfo.tableid = -1
        self.userInfo.roomid = -1
        self.ns.send(json.dumps(data))
        self.ns.process()
        self.setButtonStatus(False,False,False,False,False,False)
        self.roomName.setText(u"暂未进\n入房间")
        self.inforShow.setText(u"你已经离开\n了房间")

    # 进入房间
    def intoTable(self, item):
        # 若已经进入房间则不再处理
        if self.userInfo.isInto:
            return
        parent1 = item.parent()
        if not parent1:
            return
        parent2 = parent1.parent()
        if not parent2:
            return
        num1 = parent1.indexOfChild(item)
        num2 = parent2.indexOfChild(parent1)
        index = num2 * 5 + num1
        num = self.tableList[index]
        if num == 2:
            pass
        elif num == 1:
            data = {'sid': 100, 'cid': 1002, 'roomid': num2, 'tableid': num1, 'user': self.username}
            self.ns.send(json.dumps(data))
            self.userInfo.isInto = True
            self.setButtonStatus(True, False, False, False, True, True)
            self.userInfo.roomid = num2 + 1
            self.userInfo.tableid = num1 + 1
            self.roomName.setText(u'房间' + str(self.userInfo.roomid) + u'\n桌子'+ str(self.userInfo.tableid))
            self.inforShow.setText(u"欢迎你坐下\n")
            self.player1.setText(self.userInfo.name)
            if self.userInfo.name in self.scoreList:
                self.score_player1.setText(u"分数：" + str(self.scoreList[self.userInfo.name]))
            # 获取对手信息
            data = {'sid': 100, 'cid': 1004, 'roomid': num2, 'tableid': num1, 'user': self.username}
            self.ns.send(json.dumps(data))
            self.ns.process()
        else:
            data = {'sid': 100, 'cid': 1002, 'roomid': num2, 'tableid': num1, 'user': self.username}
            self.ns.send(json.dumps(data))
            self.ns.process()
            self.userInfo.isInto = True
            self.userInfo.opponent = None
            self.setButtonStatus(False, False, False, False, True, False)
            self.userInfo.roomid = num2 + 1
            self.userInfo.tableid = num1 + 1
            self.roomName.setText(u'房间' + str(self.userInfo.roomid) + u'\n桌子' + str(self.userInfo.tableid))
            self.inforShow.setText(u"欢迎你坐下\n")
            self.player1.setText(self.userInfo.name)
            if self.userInfo.name in self.scoreList:
                self.score_player1.setText(u"分数：" + str(self.scoreList[self.userInfo.name]))

    # 群聊
    def sendGroupMessage(self):
        text = self.groupEdit.text()
        text = unicode(text).strip()
        self.groupEdit.clear()
        if len(text) > 0:
            data = {'sid':102,'cid':1001,'message':text,'user':self.userInfo.name}
            self.ns.send(json.dumps(data))
            self.ns.process()

    # 私聊
    def sendSingleMessage(self):
        if self.userInfo.opponent != None:
            text = self.singleEdit.text()
            text = unicode(text).strip()
            self.singleEdit.clear()
            if len(text) > 0:
                data = {'sid':102,'cid':1002,'message':text,'userlist':[self.userInfo.name,self.userInfo.opponent],
                        'user':self.userInfo.name}
                self.ns.send(json.dumps(data))
                self.ns.process()

    # 定时处理函数
    def check(self):
        #定时更新信息
        self.update_trigger()
        self.ns.process()
        if self.ns.state == netstream.NET_STATE_ESTABLISHED:
            if self.reconnect:
                self.reconnect = False
                # 重新绑定用户信息
                user = {'sid': 103, 'cid': 1001, 'user': self.username}
                self.ns.send(json.dumps(user))
                if self.userInfo.isInto:
                    # 重新进房
                    data = {'sid': 100, 'cid': 1002, 'roomid': self.userInfo.roomid - 1,
                            'tableid': self.userInfo.tableid - 1, 'user': self.userInfo.name}
                    self.ns.send(json.dumps(data))
                    self.ns.process()
                if not self.userInfo.isBegin and self.userInfo.isReady:
                    # 重新发送开始信息
                    message = {'sid': 100, 'cid': 1005, 'message': 'start', 'user': self.userInfo.name,
                               'opponent': self.userInfo.opponent}
                    self.ns.send(json.dumps(message))
                    self.ns.process()
                self.setButtonStatus(self.saveStart, self.saveGive, self.saveRegret, self.saveAgain, self.saveLeave,
                                     self.saveSend)
                self.userInfo.isNext = self.saveNext
                QtGui.QMessageBox.information(self, u"提示", u"连接成功!")
            data = self.ns.recv()
            if len(data) > 0:
                data = json.loads(data)
                # 下棋消息
                if data['sid'] == 100:
                    # 房间列表信息
                    if data['cid'] == 1001:
                        self.tableList = data['tableList']
                    elif data['cid'] == 1002:
                        pass
                    elif data['cid'] == 1003:
                        self.inforShow.setText(u"你的对手离开\n了房间")
                        self.player2.setText(u"玩家2：")
                        self.score_player2.setText(u"分数：")
                        self.setButtonStatus(False, False, False, False, True, False)
                        self.userInfo.opponent = None
                    elif data['cid'] == 1004:
                        if data['opponent'] != '':
                            self.userInfo.opponent = data['opponent']
                            self.player2.setText(self.userInfo.opponent)
                            if self.userInfo.opponent in self.scoreList:
                                self.score_player2.setText(u"分数："+str(self.scoreList[self.userInfo.opponent]))
                            self.setButtonStatus(True,False,False,False,True,True)
                    elif data['cid'] == 1005:
                        if data['message'] == u'begin':
                            self.beginChess(data)
                        else:
                            self.inforShow.setText(u"你们还有一\n方未准备")
                    elif data['cid'] == 1006:
                        n = data['n']
                        m = data['m']
                        self.userInfo.updateChessBoard(n, m)
                    elif data['cid'] == 1007:
                        if data['chessType'] != NON_FLAG:
                            self.inforShow.setText(u"很遗憾，\n你输了")
                            self.musicplay.playLose()
                        else:
                            self.inforShow.setText(u"平局啦")
                            self.musicplay.playTie()
                        self.setButtonStatus(False, False, False, True, True, True)
                        self.userInfo.isNext = False
                    elif data['cid'] == 1008:
                        self.scoreList = data['scoreList']
                    elif data['cid'] == 1009:
                        self.inforShow.setText(u"对方认输，\n你赢了")
                        self.musicplay.playWin()
                        self.setButtonStatus(False, False, False, True, True, True)
                        self.userInfo.isNext = False
                    elif data['cid'] == 1010:
                        reply = QtGui.QMessageBox.question(self, u"悔棋", u"你的对手请求悔棋，是否同意？",
                                                           QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)
                        if reply == QtGui.QMessageBox.Yes:
                            data = {'sid': 100, 'cid': 1011, 'reply': 'yes', 'userlist': [self.userInfo.opponent]}
                            self.ns.send(json.dumps(data))
                            self.ns.process()
                            self.userInfo.backmove()
                        else:
                            data = {'sid': 100, 'cid': 1011, 'reply': 'no', 'userlist': [self.userInfo.opponent]}
                            self.ns.send(json.dumps(data))
                            self.ns.process()
                    elif data['cid'] == 1011:
                        if data['reply'] == 'yes':
                            QtGui.QMessageBox.information(self, u"提示",u"对手同意了你的悔棋请求")
                            self.userInfo.backmove()
                        else:
                            QtGui.QMessageBox.information(self, u"提示",u"对手拒绝了你的悔棋请求")
                        self.userInfo.isNext = True
                        self.inforShow.setText("我方下".decode('utf-8'))
                    elif data['cid'] == 1012:
                        reply = QtGui.QMessageBox.question(self, u"再来一局",
                                                           u"你的对手请求再来一局，是否同意？", QtGui.QMessageBox.Yes,
                                                           QtGui.QMessageBox.No)
                        if reply == QtGui.QMessageBox.Yes:
                            data = {'sid': 100, 'cid': 1013, 'reply': 'yes', 'userlist': [self.userInfo.opponent],
                                    'white': self.userInfo.opponent}
                            self.ns.send(json.dumps(data))
                            self.ns.process()
                            self.beginChess(data)
                        else:
                            data = {'sid': 100, 'cid': 1013, 'reply': 'no', 'userlist': [self.userInfo.opponent]}
                            self.ns.send(json.dumps(data))
                            self.ns.process()
                    elif data['cid'] == 1013:
                        if data['reply'] == 'yes':
                            QtGui.QMessageBox.information(self, u"提示", u"对手同意再来一局")
                            self.beginChess(data)
                        else:
                            QtGui.QMessageBox.information(self, u"提示", u"对手拒绝再来一局")

                # 聊天消息
                elif data['sid'] == 102:
                    if data['cid'] == 1001:
                        groupMsg = data['user']+': '+\
                                   str(time.strftime('%H:%M:%S',time.localtime(time.time())))+'\n'+data['message']+'\n'
                        self.groupTalk.insertPlainText(groupMsg)
                        self.groupTalk.setTextCursor(self.groupTalk.textCursor())
                    elif data['cid'] == 1002:
                        singleMsg = data['user']+': '+\
                                    str(time.strftime('%H:%M:%S',time.localtime(time.time())))+'\n'+data['message']+'\n'
                        self.singleTalk.insertPlainText(singleMsg)
                        self.singleTalk.setTextCursor(self.singleTalk.textCursor())
                # 心跳消息
                elif data['sid'] == 105:
                    pass
            else:
                pass
        elif self.ns.status() == netstream.NET_STATE_STOP:
            # 服务器宕机客户端重连
            logging.error(u"服务器宕机，正在重连...")
            self.saveNext = self.userInfo.isNext
            self.userInfo.isNext = False
            self.saveStart = self.start.isEnabled()
            self.saveGive = self.giveUp.isEnabled()
            self.saveRegret = self.undo.isEnabled()
            self.saveAgain = self.again.isEnabled()
            self.saveLeave = self.left.isEnabled()
            self.saveSend = self.singleSend.isEnabled()
            self.setButtonStatus(False, False, False, False, False, False)
            self.ns.connect(self.ip, self.port)
        elif self.ns.status() == netstream.NET_STATE_CONNECTING:
            # 服务器宕机客户端重连
            self.ns.connect(self.ip, self.port)
            self.reconnect = True

    # 定期触发更新房间列表，分数排名，检索对手以及往服务器发送心跳包
    def update_trigger(self):
        # 更新房间桌子列表
        self.updateRoom()
        # 更新排行榜
        self.updateRank()
        # 更新分数
        if self.userInfo.isInto:
            if self.userInfo.name in self.scoreList:
                self.score_player1.setText(u"分数："+str(self.scoreList[self.userInfo.name]))
            if self.userInfo.opponent != None and self.userInfo.opponent in self.scoreList:
                self.score_player2.setText(u"分数："+str(self.scoreList[self.userInfo.opponent]))
        # 检索对手
        if self.userInfo.opponent == None  and self.loopCount == 0:
            self.loopCount = 40
            if self.userInfo.tableid != -1:
                data = {'sid':100, 'cid':1004,'roomid':self.userInfo.roomid - 1,
                        'tableid':self.userInfo.tableid - 1,'user':self.userInfo.name}
                self.ns.send(json.dumps(data))
                self.ns.process()
        else:
            if self.loopCount == 0:
                self.loopCount = 40
            self.loopCount -= 1
        # 每隔5秒发送心跳包
        if self.tickCount == 0:
            self.tickCount = 100
            data = {'sid':105,'cid':1001}
            self.ns.send(json.dumps(data))
            self.ns.process()
        else:
            self.tickCount -= 1

    # 更新房间桌子列表
    def updateRoom(self):
        item0 = self.room.invisibleRootItem()
        item1 = item0.child(0)
        childCount = item1.childCount()
        for i in xrange(childCount):
            itemChild1 = item1.child(i)
            num = 0
            for j in xrange(0, 5):
                num += self.tableList[i * 5 + j]
                if itemChild1:
                    itemChild2 = itemChild1.child(j)
                    itemChild2.setText(0, u'桌子' + str(j + 1) + '(' + str(
                        self.tableList[i * 5 + j]) + '/2)')
            if itemChild1:
                itemChild1.setText(0, u'房间' + str(i + 1) + '(' + str(num) + '/10)')

    # 更新排行榜
    def updateRank(self):
        self.scoreRank.clear()
        data = sorted(self.scoreList.iteritems(), key=lambda d: d[1], reverse=True)
        self.scoreRank.addItem(u'玩家'.ljust(18, ' ') + u'分数')
        for i in xrange(len(data)):
            # 显示前10名
            if i >= 10:
                break
            self.scoreRank.addItem(unicode(data[i][0]).ljust(20, ' ') + str(data[i][1]))

    # 开始对战
    def beginChess(self, data):
        # 清除棋盘
        self.userInfo.clearChessBoard()
        self.inforShow.setText(u"可以开始\n比赛了")
        self.musicplay.playStart()
        self.setButtonStatus(False, True, True, False, False, True)
        self.userInfo.isBegin = True
        self.chessBoard.mouseReleaseEvent = self.releaseAction
        if data['white'] == self.userInfo.name:
            self.inforShow.setText(u"你是白棋，\n你先下")
            self.userInfo.chessType = WHITE_FLAG
            self.userInfo.isNext = True
        else:
            self.inforShow.setText(u"你是黑棋，\n你后手")
            self.userInfo.chessType = BLACK_FLAG
            self.userInfo.isNext = False

    # 鼠标左键按下监听
    def releaseAction(self,event):
        if event.button() == Qt.LeftButton:
            self.paint(event.pos().x(), event.pos().y())

    # 描绘棋子
    def paint(self, x, y):
        n, m = self.userInfo.pressEvent(x,y)
        if n != -1:
            data = {'sid': 100, 'cid': 1006, 'm': m, 'n': n, 'userlist': [self.userInfo.opponent]}
            self.ns.send(json.dumps(data))
        if self.userInfo.checkWin(n, m):
            self.userInfo.isNext = False
            self.setButtonStatus(False, False, False, True, True, True)
            self.inforShow.setText(u"恭喜你赢了")
            self.musicplay.playWin()
            data = {'sid':100,'cid':1007,'winner':self.userInfo.name,'loser':self.userInfo.opponent,'chessType':self.userInfo.chessType}
            self.ns.send(json.dumps(data))
            self.ns.process()
        elif self.userInfo.checkTie():
            self.userInfo.isNext = False
            self.setButtonStatus(False, False, False, True, True, True)
            self.inforShow.setText(u"和局啦")
            self.musicplay.playTie()
            data = {'sid': 100, 'cid': 1007, 'winner':self.userInfo.name,'loser':self.userInfo.opponent, 'chessType': NON_FLAG}
            self.ns.send(json.dumps(data))
            self.ns.process()

    # 启动游戏客户端
    def startup(self):
        self.__init_config()
        self.__init_ui()
        self.timer.start(50)

    # 关闭时候清理资源
    def closeEvent(self, event):
        data = {'sid': 101, 'cid': 1001, 'user': self.username}
        self.ns.send(json.dumps(data))
        if self.userInfo.isInto:
            data = {'sid':100,'cid':1003,'roomid':self.userInfo.roomid - 1,'tableid':self.userInfo.tableid - 1,
                    'user':self.userInfo.name,'opponent':self.userInfo.opponent}
            self.ns.send(json.dumps(data))
            self.ns.process()
        # 防止因退出而丢失消息
        time.sleep(0.1)